﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
#if USING_UNITY
using UnityEngine;
#endif
using com.susi.util;
#if ODIN_INSPECTOR
using Sirenix.OdinInspector;
#endif
namespace com.susi.util.toolkit
{
    /// <summary>
    /// 将<see cref="EventBag{TKey, TItem}"/>包装成列表的类
    /// <br>无法定义排序</br>
    /// <br>已知问题：不兼容Odin，因为Odin以List身份对待TagBag并调用到Set索引器</br>
    /// </summary>
#if ODIN_INSPECTOR
    [ShowInInspector,Obsolete]
#endif
    public class EventTagBag<TKey, TItem> : IDictionary<TKey, EventList<TItem>>,ICollection<TItem>, IDisposaEventer, IDisposaEventer<EventBag<TKey, TItem>>
        where TItem : class
    {
#if ODIN_INSPECTOR
        [LabelText("被包装的包包"), ShowInInspector]
#endif
        public EventBag<TKey, TItem> InnerBag { get; private set; } = new EventBag<TKey, TItem>();
        Func<TItem, TKey> KeySelector;

#pragma warning disable IDE1006 // 命名样式
        public event Func<TItem, bool> AddingFliter
        {
            add => InnerBag.AddingFliter += value;
            remove => InnerBag.AddingFliter -= value;
        }
        /// <summary>
        /// 当本对象释放的时候，RemovingFliter会被无视
        /// </summary>
        public event Func<TItem, bool> RemovingFliter
        {
            add => InnerBag.RemovingFliter += value;
            remove => InnerBag.RemovingFliter -= value;
        }
#pragma warning restore IDE1006 // 命名样式
        public event Action<TItem> onAddedEvent
        {
            add => InnerBag.onAddedEvent += value;
            remove => InnerBag.onAddedEvent -= value;
        }
        public event Action<TItem> onRemovedEvent
        {
            add => InnerBag.onRemovedEvent += value;
            remove => InnerBag.onRemovedEvent -= value;
        }
        public event Action onChangedEvent
        {
            add => InnerBag.onChangedEvent += value;
            remove => InnerBag.onChangedEvent -= value;
        }
        public event Action onDisposingEvent
        {
            add => InnerBag.onDisposingEvent += value;
            remove => InnerBag.onDisposingEvent -= value;
        }
        public event Action<EventBag<TKey, TItem>> onDisposingTEvent
        {
            add => InnerBag.onDisposingTEvent += value;
            remove => InnerBag.onDisposingTEvent -= value;
        }

        public EventTagBag(Func<TItem, TKey> keySelector)
        {
            KeySelector = keySelector ?? throw new ArgumentNullException(nameof(keySelector));
        }


        /// <summary>
        /// 不支持set
        /// </summary>
        public TItem this[int index]
        {
            get
            {

                return ((IEnumerable<TItem>)this).GetByIndex(index);
                //var itor = GetEnumerator()
                //int count = -1;
                //while (itor.MoveNext())
                //{
                //    count++;
                //    if (count == index)
                //    {
                //        return itor.Current;
                //    }
                //}
                //return null;
            }
            set
            {
                var item = this[index];
                Remove(item);
                Add(value);
            }
        }

        public IEnumerable<TItem> this[TKey tag]
        {
            get
            {
                if (InnerBag.TryGetValue(tag, out var evlst))
                {
                    return evlst;
                }
                return Enumerable.Empty<TItem>();
            }
        }
        public int Count
        {
            get
            {
                var v = from lst in InnerBag
                        from item in lst.Value
                        select item;
                return v.Count();
            }
        }
        /// <summary>
        /// 永远返回false
        /// </summary>
        public bool IsReadOnly => false;

        public ICollection<TKey> Keys => InnerBag.Keys;

        public ICollection<EventList<TItem>> Values => InnerBag.Values;

        EventList<TItem> IDictionary<TKey, EventList<TItem>>.this[TKey key] { get => InnerBag[key]; set => InnerBag[key] = value; }

        public void Add(TItem item)
        {
            if (item == null) return;
            InnerBag.AddToInnerList(KeySelector(item), item);
        }

        public void Clear()
        {
            InnerBag.Clear();
        }

        public bool Contains(TItem item)
        {
            return InnerBag.Contains(item);
        }

        public void CopyTo(TItem[] array, int arrayIndex)
        {
            if (array == null) throw new ArgumentNullException(nameof(array));
            if (arrayIndex >= array.Length) throw new ArgumentOutOfRangeException(nameof(arrayIndex));
            var itor = this.GetEnumerator();
            for (; arrayIndex < array.Length && itor.MoveNext(); arrayIndex++)
            {
                array[arrayIndex] = itor.Current;
            }
        }

        public IEnumerator<TItem> GetEnumerator()
        {
            return (from lst in InnerBag.Values
                    from item in lst
                    select item).GetEnumerator();
        }

        public int IndexOf(TItem item)
        {
            int idx = -1;
            var itor = this.GetEnumerator();
            while (itor.MoveNext())
            {
                idx++;
                if (itor.Current == item) return idx;
            }
            return -1;
        }
        /// <summary>
        /// 不支持
        /// </summary>
        [Obsolete]
        public void Insert(int index, TItem item)
        {
            throw new NotSupportedException();
        }

        public bool Remove(TItem item)
        {
            return InnerBag.RemoveValue(item);
        }

        public void RemoveAt(int index)
        {
            var item = InnerBag.ElementAt(index);
            InnerBag.Remove(item);
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        public void Dispose()
        {
            InnerBag.Dispose();
            InnerBag = null;
            KeySelector = null;
        }

        public void Add(TKey key, EventList<TItem> value)
        {
            InnerBag.Add(key, value);
        }

        public bool ContainsKey(TKey key)
        {
            return InnerBag.ContainsKey(key);
        }

        public bool Remove(TKey key)
        {
            return InnerBag.Remove(key);
        }

        public bool TryGetValue(TKey key, out EventList<TItem> value)
        {
            return InnerBag.TryGetValue(key, out value);
        }

        public void Add(KeyValuePair<TKey, EventList<TItem>> item)
        {
            InnerBag.Add(item);
        }

        public bool Contains(KeyValuePair<TKey, EventList<TItem>> item)
        {
            return InnerBag.Contains(item);
        }

        public void CopyTo(KeyValuePair<TKey, EventList<TItem>>[] array, int arrayIndex)
        {
            InnerBag.CopyTo(array, arrayIndex);
        }

        public bool Remove(KeyValuePair<TKey, EventList<TItem>> item)
        {
            return InnerBag.Remove(item);
        }

        IEnumerator<KeyValuePair<TKey, EventList<TItem>>> IEnumerable<KeyValuePair<TKey, EventList<TItem>>>.GetEnumerator()
        {
            return InnerBag.GetEnumerator();
        }
        /// <summary>
        /// 按类别放好物品
        /// </summary>
        public void AddRange(IEnumerable<TItem> items)
        {
            var dic = from item in items
                      let key = KeySelector(item)
                      group item by key into g
                      select g;
            foreach (var kl in dic)
            {
                InnerBag.AddRange(kl.Key, kl);
            }
        }
    }
}
